﻿// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

using System;

namespace core
{
    /// <summary>Trieda ISplitContainer</summary>
	public class ISplitContainer : System.Windows.Forms.SplitContainer
	{
        public delegate void SplitterChangeEvent(object pSender, double pPosition); // Event SplitterChanged a SplitterChanging

        public double MinSplitterPosition, MaxSplitterPosition; // Minimalna a maximalna pozicia oddelovaca
        public event SplitterChangeEvent SplitterChanged, SplitterChanging;

        protected double FSplitterPosition; // Aktualna pozicia oddelovaca v percentach
        protected bool FInternalUpdate; // Priznak internej aktualizacie pozicie
        protected bool FUserResizing; // Priznak zmeny pozicie oddelovaca uzivatelom

        /// <summary>Property: SplitterPosition</summary>
        public double SplitterPosition
        {
            get
            {
                return FSplitterPosition;
            }
            set
            {
                if (FSplitterPosition == value) return; // Ziadna zmena?
                if (FSplitterPosition < MinSplitterPosition) FSplitterPosition = MinSplitterPosition; // Vsadim do povoleneho rozsahu
                if (FSplitterPosition > MaxSplitterPosition) FSplitterPosition = MaxSplitterPosition;
                FSplitterPosition = value;
                UpdateSplitterPosition(value);
            }
        }
        /// <summary>Property: VerticalPanels</summary>
        public bool VerticalPanels
        {
            get
            {
                return Orientation == System.Windows.Forms.Orientation.Vertical;
            }
            set
            {
                if (VerticalPanels != value)
                {
                    FInternalUpdate = true;
                    Orientation = value ? System.Windows.Forms.Orientation.Vertical : System.Windows.Forms.Orientation.Horizontal;
                    FInternalUpdate = false;
                    UpdateSplitterPosition(FSplitterPosition);
                }
            }
        }
        /// <summary>Property: PanelsVisibility</summary>
        public int PanelsVisibility
        {
            get
            {
                int R = 0;
                if (!Panel1Collapsed) R |= 1; // Vytvorim masku viditelnosti
                if (!Panel2Collapsed) R |= 2;
                return R;
            }
            set
            {
                int V = value & 0x3;
                if (V == PanelsVisibility) return; // Ziadna zmena?
                if (V == 0) return; // Nepripustna hodnota?
                Panel1Collapsed = (V & 0x1) == 0; // Aplikujem
                Panel2Collapsed = (V & 0x2) == 0;
                if (V == 3) UpdateSplitterPosition(FSplitterPosition);
            }
        }
        /// <summary>Property: LeftPanelVisible</summary>
        public bool LeftPanelVisible
        {
            get
            {
                return (PanelsVisibility & 0x1) != 0;
            }
            set
            {
                int V = PanelsVisibility;
                if (value)
                {
                    PanelsVisibility = V | 1;
                }
                else
                {
                    PanelsVisibility = V == 1 ? 2 : V & 2;
                }
            }
        }
        /// <summary>Property: RightPanelVisible</summary>
        public bool RightPanelVisible
        {
            get
            {
                return (PanelsVisibility & 0x2) != 0;
            }
            set
            {
                int V = PanelsVisibility;
                if (value)
                {
                    PanelsVisibility = V | 2;
                }
                else
                {
                    PanelsVisibility = V == 2 ? 1 : V & 1;
                }
            }
        }

        /// <summary>Aktualizacia pozicia splittera</summary>
        /// <param name="pValue">pozicia oddelovaca v percentach</param>
        protected void UpdateSplitterPosition(double pValue)
        {
            if (!Visible) return;
            FInternalUpdate = true; // Nastavim priznak
            int Value = (int)TransformPosition(pValue, false);
            if (Value >= 10) SplitterDistance = Value;
            FInternalUpdate = false; // Zhodim priznak
        }
        /// <summary>Prevod pozicie z percent na body a opacne</summary>
        /// <param name="pValue">hodnota</param>
        /// <param name="pValueInPercent">priznak vstupu v percentach</param>
        /// <returns>vysledok</returns>
        protected double TransformPosition(double pValue, bool pValueInPercent)
        {
            int W = Orientation == System.Windows.Forms.Orientation.Vertical ? ClientSize.Width : ClientSize.Height;
            if (pValueInPercent) // Percenta na body?
            {
                W -= SplitterWidth;
                return Math.Round( (pValue/ (double)W) * 100.0, 1);
            }
            else
            {
                W -= SplitterWidth;
                return Math.Round((double)W * (pValue / 100.0), 0);
            }
        }

        /// <summary>Event: SplitterMoved</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_SplitterMoved(object pSender, System.Windows.Forms.SplitterEventArgs e)
        {
            if (!FUserResizing) return; // Nie je zmena od uzivatela
            FUserResizing = false; // Zrusim priznak zmeny uzivatelom
            if (FInternalUpdate) return; // Interna aktualizacia?

            double D = TransformPosition((double)(Orientation == System.Windows.Forms.Orientation.Vertical ? e.SplitX : e.SplitY), true); // Ziskam poziciu
            if (D < MinSplitterPosition) D = MinSplitterPosition;
            if (D > MaxSplitterPosition) D = MaxSplitterPosition;

            UpdateSplitterPosition(D);
            FSplitterPosition = D;
            if (SplitterChanged == null) return; // Ziaden event?
            SplitterChanged(this, D); // Volam event
        }
        /// <summary>Event: SplitterMoving</summary>
        /// <param name="pSender">zdroj</param>
        /// <param name="e">parameter</param>
        protected void Event_SplitterMoving(object pSender, System.Windows.Forms.SplitterCancelEventArgs e)
        {
            if (FInternalUpdate) return; // Interna aktualizacia?
            FUserResizing = true; // Nastavim priznak zmeny uzivatelom
            if (SplitterChanging == null) return; // Ziaden event?

            double D = TransformPosition((double)(Orientation == System.Windows.Forms.Orientation.Vertical ? e.SplitX : e.SplitY), true); // Ziskam poziciu
            if (D < MinSplitterPosition) return;
            if (D > MaxSplitterPosition) return;

            if (D == FSplitterPosition)
            {
                if (SplitterChanged != null) SplitterChanged(this, D); // Volam event
            }
            else SplitterChanging(this, D); // Volam event
        }

        /// <summary>Metoda: OnResize</summary>
        /// <param name="e">parameter</param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e); // Volam predchodcu
            if (FInternalUpdate) return; // Je interna aktualizacia?
            UpdateSplitterPosition(FSplitterPosition);
        }

        /// <summary>Konstruktor</summary>
        public ISplitContainer() : base()
        {
            //SetStyle(System.Windows.Forms.ControlStyles.Selectable, false); // Nastavim styl

            FSplitterPosition = 50.0; // Inicializacia
            FInternalUpdate = false;
            MinSplitterPosition = 10.0; MaxSplitterPosition = 90.0;

            UpdateSplitterPosition(FSplitterPosition); // Aktualizujem poziciu oddelovaca
            SplitterMoved += Event_SplitterMoved; SplitterMoving += Event_SplitterMoving; // Nastavim eventy
        }
	}
}
